home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_200
/
297_01
/
prtypes.h
< prev
Wrap
C/C++ Source or Header
|
1991-12-19
|
13KB
|
318 lines
/* prtypes.h */
/* The basic data structures of Small Prolog.
* This is the file that you need to understand before the others
* if you want to extend Small Prolog.
* 12/21/91 added ND_SUCCESS
*/
#include "prolog.h" /* compilation switches */
/***************************************************************************
Variables.
Variables in Small Prolog begin with a capital letter or an underscore.
The parser throws away the name and only retains an offset. The variables
are numbered 0,1,2,... in order of their appearance in a clause.
The maximum number of variables is MAX_VAR.
For optimisation purposes the numbers 0,1,2, etc are multiplied
by sizeof(struct subst) as soon as the variables are parsed. This
is the real offset. The offset is used to efficiently lookup the
corresponding molecule in the substitution stack.
****************************************************************************/
typedef int varindx; /* variables have a unique "offset" in a clause */
typedef short clflag_t;/* to contain flags for clauses */
/***************************************************************************
Integers.
Integers are the same size as pointers.
***************************************************************************/
typedef long integer;
/***************************************************************************
Strings.
Strings are not stored in a hash table, so if you are going to use the
same string lots of times you better be careful you dont consume too
much memory.
***************************************************************************/
typedef char *string_ptr_t;
/***************************************************************************
Reals.
You might want to just use floats here, but real multiplication usually gets
done in doubles anyway.
You might want to do away with reals altogether.
***************************************************************************/
typedef double real;
typedef double *real_ptr_t;
/****************************************************************************
Chars . These were added as an afterthought because they were used in an
application.
****************************************************************************/
typedef unsigned char uchar_t; /* I prefer insisting on unsigned */
/***************************************************************************
Integer returning functions.
These are what builtins are made from.
You will need to be more precise with Zortech C.
***************************************************************************/
typedef int (* intfun)();
/***************************************************************************
Clauses.
Clauses are organised in singly linked lists, one for each predicate
other than a builtin. This does not support an efficient access to a
clause within a clause packet. Remember that this is just a minimal
Prolog.
Each variable comes with a field called nvar_goals which is the
number of distinct variables in it , multiplied by sizeof(struct subst).
The number of variables is not going to vary during the execution. Therefore
so as not to waste time this is stored once and for all so that
the right amount of substitution stack can be allocated when this
clause's head becomes a candidate for unification.
The Head and Goal of the clause are separated for a small efficiency
consideration only.
***************************************************************************/
typedef struct clause {
struct clause *next_clause;/* next in packet or NULL */
struct node *head_clause; /* unify goal with this */
struct node *goals_clause; /* a list if a rule */
varindx nvar_clause; /* number of variables */
clflag_t flags_clause; /* suplementary flags
I only use this in clean_temp()
*/
}*clause_ptr_t;
/* C is a clause pointer */
#define CLAUSEPTR_HEAD(C) (C->head_clause) /* returns a nodeptr */
#define CLAUSEPTR_GOALS(C) (C->goals_clause) /* returns a nodeptr */
#define CLAUSEPTR_NVARS(C) (C->nvar_clause)
#define CLAUSEPTR_NEXT(C) (C->next_clause)
#define CLAUSEPTR_FLAGS(C) (C->flags_clause)
#define IS_FACT(C) IS_NIL(CLAUSEPTR_GOALS(C))
/***************************************************************************
Atoms.
Atoms are identifiers that can serve as relation names or constants.
Atoms are not to be confused with atomic formulae.
They have a field which points directly to either a builtin or a
clause packet, or just NULL.
Atoms are stored in a hash table (see prhash.c ).
In this simple implementation atoms are all stored in the heap,
and so dont ever disappear on backtracking.
***************************************************************************/
typedef union {
intfun primitive;/* i.e. builtin */
clause_ptr_t clause;
}procedure_ptr_t;
typedef struct atom {
string_ptr_t name;
struct atom *hash_link; /* in hash table */
procedure_ptr_t proc;
} *atom_ptr_t;
#define ATOMPTR_BUILTIN(A) (A->proc).primitive
#define ATOMPTR_CLAUSE(A) (A->proc).clause
#define ATOMPTR_NAME(A) (A->name)
/***************************************************************************
Objects and their types.
To distinguish integers, reals etc they are stored in "nodes"
which contains the objects and a type flag. You might want to include
a mark bit for a garbage collector (see the sourcecode of Xlisp) in the
type field.
You will notice that integers are stored directly in an object. This
avoids an indirection. Variable offsets likewise.
***************************************************************************/
typedef short objtype_t; /* used to distinguish amongst the types */
#ifdef MIX
#undef STRING /* defined in Mix Power C */
#endif
/* values for objtype_t - these need to be numbered from 0 up
* increasing by steps of 1 (see prerror.c , the global
* Typenames). Of course this is where enums could be used.
*/
#define ATOM 0
#define VAR 1
#define STRING 2
#define INT 3
#define PAIR 4
#define CLAUSE 5
#define REAL 6
/*
#define CHARACTER 7
*/
typedef union {
integer int_val; /* value of integer */
varindx var_offset; /* offset of var */
struct pair *dbl_val; /* usual value */
string_ptr_t string_val; /* pointer to string */
atom_ptr_t atom_val; /* pointer to atom */
clause_ptr_t clause_val; /* points to clause */
#ifdef REAL
real_ptr_t realp_val; /* pointer to double */
#endif
#ifdef CHARACTER
uchar_t char_val; /* char */
#endif
}obj_ptr_t;
/* this is the way we handle objetcs in general - a node
carries its own type which lets us know how to access
the object. A list is made from pairs each of which is
a couple of nodes.
*/
typedef struct node {
objtype_t type;
obj_ptr_t object;
} *node_ptr_t;
/* Y is an node_ptr_t */
#define NODEPTR_TYPE(Y) (Y)->type
#define NODEPTR_OBJECT(Y) (Y)->object
#define NODEPTR_ATOM(Y) (NODEPTR_OBJECT(Y)).atom_val
#define NODEPTR_STRING(Y) (NODEPTR_OBJECT(Y)).string_val
#define NODEPTR_OFFSET(Y) (NODEPTR_OBJECT(Y)).var_offset
#define NODEPTR_INT(Y) (NODEPTR_OBJECT(Y)).int_val
#define NODEPTR_PAIR(Y) (NODEPTR_OBJECT(Y)).dbl_val
#define NODEPTR_CLAUSE(Y) (NODEPTR_OBJECT(Y)).clause_val
#define NODEPTR_HEAD(Y) &((((Y)->object).dbl_val)->head)
#define NODEPTR_TAIL(Y) &((((Y)->object).dbl_val)->tail)
#ifdef REAL
#define NODEPTR_REALP(Y) ((NODEPTR_OBJECT(Y)).realp_val)
#define NODEPTR_REAL(Y) *NODEPTR_REALP(Y)
#endif
#ifdef CHARACTER
#define NODEPTR_CHARACTER(Y) (NODEPTR_OBJECT(Y)).char_val
#endif
#define IS_NIL(Y) ((NODEPTR_TYPE(Y)==ATOM) && (NODEPTR_ATOM(Y) == Nil))
/***************************************************************************
Pairs.
A list is either a pair or the empty list (an atom). This makes
Small Prolog look like Lisp.
In Small Prolog all terms are built from lists. This gives uniformity
at the expense (it seems) of a slight loss of speed. In some implementations
terms are built as arrays.
************************